﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEditor;
using System.IO;

namespace hxweditor { 

    //场景打包逻辑
    public class SceneAssetBundleTool
    {
        public static List<AssetBundleBuild> GetSceneAssetBundleBuild(string Dir)
        {
            Dictionary<string, List<string>> outPutFiles = new Dictionary<string, List<string>>();

            Dir = PathTool.FormationPath(Dir);
            if (!Directory.Exists(Dir))
            {
                Debug.LogError("找不到目录:" + Dir);
                return new List<AssetBundleBuild>();
            }

            //场景依赖资源列表
            Dictionary<string, string[]> sceneDependenciesDic = new Dictionary<string, string[]>();

            //资源引用计数
            Dictionary<string,int> dependenciesCountDic = new Dictionary<string,int>();

            //拿到所有场景目录路径的列表
            string[] SceneDirList = Directory.GetDirectories(Dir);
            //遍历每个场景目录
            foreach (string sceneDir in SceneDirList)
            {
                //拿到里面所有的场景 以assets目录开头
                List<string> sceneList = new List<string>();
                string[] sceneArray = Directory.GetFiles(sceneDir);
                foreach (string scenePath in sceneArray)
                {
                    string sp = PathTool.RemoveTo(scenePath, PathTool.AssetsFlag);
                    sceneList.Add(sp);
                }

                //递归拿到场景列表的依赖引用资源路径列表
                string[] dependencies = AssetDatabase.GetDependencies(sceneList.ToArray(),true);

                sceneDependenciesDic[sceneDir] = dependencies;

                //引用了一次计一次
                foreach (string asset in dependencies)
                {
                    if(!dependenciesCountDic.ContainsKey(asset))
                        dependenciesCountDic[asset] = 0;
                    dependenciesCountDic[asset] ++;
                }
            }

            //将资源分开共公资源和场景独有资源
            List<string> publicAssets = new List<string>();
            Dictionary<string, string[]> sceneAssetDic = new Dictionary<string, string[]>();

            foreach (var dp in sceneDependenciesDic)
            {
                List<string> sceneAssetsList = new List<string>();
                foreach (string assetsPath in dp.Value)
                {
                    int count = 0;
                    if (dependenciesCountDic.ContainsKey(assetsPath))
                        count = dependenciesCountDic[assetsPath];
                    if (count > 1){
                        if (publicAssets.IndexOf(assetsPath) == -1)
                            publicAssets.Add(assetsPath);
                    }
                    else
                    {
                        sceneAssetsList.Add(assetsPath);
                    }
                }
                sceneAssetDic[dp.Key] = sceneAssetsList.ToArray();
            }

            //公共资源包
            GetPublicBundleBuildList(publicAssets.ToArray(), "AssetBundle/Scene/Public","Public", outPutFiles);
            //场景依赖资源包
            foreach (var sc in sceneAssetDic)
            {
                string sceneDir = sc.Key;
                string bundlePath = PathTool.RemoveTo(sceneDir, PathTool.AssetBundleFlag);
                string[] sceneAssets = sc.Value;
                GetPublicBundleBuildList(sceneAssets, bundlePath, "Dependenct", outPutFiles);
            }

            //场景包
            foreach (string SceneDir in SceneDirList)
            {
                GetSceneBundleBuildList(SceneDir,AssetBundleTool.getFilter(AssetBundleBuildType.scene),outPutFiles);
            }

            return BuildAssetBundleBuild(outPutFiles);
        }



        /// <summary>
        /// 将该文件列表生成若干个小包
        /// </summary>
        /// <param name="assets"></param>
        /// <param name="bundlePath"></param>
        /// <param name="output"></param>
        private static void GetPublicBundleBuildList(string[] assets,string bundlePath,string bundleName,Dictionary<string,List<string>> output)
        {
            Array.Sort(assets, (a, b) => { return a.CompareTo(b); });
            //包索引
            int packageIndex = 0;
            //当前字节数
            long byteLenght = 0;

            List<string> ignoreExtList = new List<string>() { ".unity",".cs",".shader",".asset"};

            foreach (string asset in assets)
            {
                FileInfo info = new FileInfo(asset);
                if (ignoreExtList.IndexOf(info.Extension) > -1) continue;
                if (byteLenght + info.Length > 1024 * 1024 * 5) 
                {
                    packageIndex++;
                    byteLenght = 0;
                }

                string bundleNameFullName = bundlePath + "/" + bundleName + packageIndex;

                byteLenght += info.Length;
                if (!output.ContainsKey(bundleNameFullName))
                    output[bundleNameFullName] = new List<string>();
                output[bundleNameFullName].Add(asset);
            }
        }

        private static void GetSceneBundleBuildList(string targetPath, string[] filters, Dictionary<string, List<string>> output)
        {
            string[] fileList = Directory.GetFiles(targetPath);
            DirectoryInfo info = new DirectoryInfo(targetPath);
            string assetBundlePath = PathTool.RemoveTo(targetPath, PathTool.AssetBundleFlag) + "/" + info.Name;
            foreach (string f in fileList)
            {
                string filePath = f;
                //格式化该文件路径
                filePath = PathTool.FormationPath(filePath);
                //如果后缀符合
                if (ContaisExt(filePath, filters))
                {
                    if (!output.ContainsKey(assetBundlePath))
                        output[assetBundlePath] = new List<string>();
                    output[assetBundlePath].Add(PathTool.RemoveTo(filePath,PathTool.AssetsFlag));
                }
            }
        }

        /// <summary>
        /// 创建 AssetBundleBuild bundle结构，可以打到包中的后缀，ab名分割标志，asset分割标志
        /// </summary>
        /// <returns></returns>
        private static List<AssetBundleBuild> BuildAssetBundleBuild(Dictionary<string, List<string>> bundleList)
        {
            List<AssetBundleBuild> result = new List<AssetBundleBuild>();

            foreach (var info in bundleList)
            {

                List<string> assets = new List<string>();
                foreach (string assetPath in info.Value)
                {
                    string path = assetPath;
                    path = PathTool.FormationPath(path);
                    assets.Add(path);
                }
                if (assets.Count > 0)
                {
                    AssetBundleBuild ab = new AssetBundleBuild();
                    ab.assetBundleName = PathTool.FormationPath(info.Key);
                    ab.assetNames = assets.ToArray();
                    result.Add(ab);
                }
            }
            return result;
        }

        //后缀名是否符合
		private static bool ContaisExt (string filePath, string[] filters)
		{
            string ext = Path.GetExtension(filePath);
			foreach (string extItem in filters) {
				if (ext.ToLower () == extItem.ToLower ())
					return true;
			}
			return false;
		}


    }

}
